import { ForbiddenException, Injectable } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { In, Repository } from 'typeorm';
import { CreateCourseDto } from './dto/create-course.dto';
import { UpdateCourseDto } from './dto/update-course.dto';
import { Course } from './entities/course.entity';
import { GetCourseDto } from './dto/get-course-dto';
import { conditionUtilsSelect } from '../utils/db.help';

@Injectable()
export class CourseService {
  constructor(
    @InjectRepository(Course)
    private courseRepository: Repository<Course>,
  ) {}

  async create(createCourseDto: CreateCourseDto) {
    const res = await this.findName(createCourseDto.name);
    if (res) {
      throw new ForbiddenException('课程名重复');
    }
    return this.courseRepository.save(createCourseDto);
  }

  findName(name: string) {
    return this.courseRepository.findOne({ where: { name } });
  }

  async findAll(query: GetCourseDto) {
    const { page, limit, name, attribute, teacher_id, major_id } = query;
    const conditions = [
      { field: 'name', value: name },
      { field: 'attribute', value: attribute },
      { field: 'teacher_id', value: teacher_id },
      { field: 'major_id', value: major_id },
    ];
    const queryBuilder = await this.courseRepository.createQueryBuilder(
      'course',
    );
    const newQueryBuilder = await conditionUtilsSelect<Course>(
      queryBuilder,
      conditions,
      'course',
    );
    const count = await newQueryBuilder.getCount();
    const content = await newQueryBuilder
      .leftJoinAndSelect('course.teacher', 'teacher')
      .leftJoinAndSelect('course.major', 'major')
      .skip((page - 1) * limit || 0)
      .take(limit || 10)
      .getMany();
    return {
      content,
      totalElements: count,
      totalPages: Number(page || 1),
    };
  }

  async findOne(id: number) {
    return await this.courseRepository.findOne({ where: { id } });
  }

  async update(id: number, updateCourseDto: UpdateCourseDto) {
    const res = await this.findOne(id);
    if (!res?.id) {
      throw new ForbiddenException('课程不存在！');
    }
    const newStudent = this.courseRepository.merge(res, updateCourseDto);
    return await this.courseRepository.save(newStudent);
  }

  async remove(id: number) {
    const res = await this.findOne(id);
    if (res?.id) {
      const content = await this.courseRepository.delete({ id: res.id });
      if (content.affected === 1) {
        return res;
      }
      throw new ForbiddenException('删除失败！');
    }
    throw new ForbiddenException('课程不存在！');
  }

  // 返回实体
  async returnCourseEntities(ids: number[]) {
    return await this.courseRepository.find({
      where: {
        id: In(ids),
      },
    });
  }

  /**
   * 模块名:课程数量增加减少事务
   * @param id 课程id
   * @param exitOrNot 添加课程:true or 退课程:false
   */
  async transferCourse(id: number, exitOrNot = true) {
    try {
      return await this.courseRepository.manager.transaction(
        async (manager) => {
          const res = await this.findOne(id);
          if (exitOrNot && res.realityPeopleNumber < res.planPeopleNumber) {
            return manager.save(Course, {
              id,
              realityPeopleNumber: res.realityPeopleNumber + 1,
            });
          }
          if (
            !exitOrNot &&
            res.planPeopleNumber > 0 &&
            res.realityPeopleNumber < res.planPeopleNumber
          ) {
            return manager.save(Course, {
              id,
              realityPeopleNumber: res.realityPeopleNumber - 1,
            });
          }
          throw new ForbiddenException('课程已经选满');
        },
      );
    } catch (error) {
      throw new ForbiddenException(error);
    }
  }
}
